<template>
  <div class="tree-card-box" :style="treeStyle || {}">
    <div v-if="treeConfig.title" class="title-box">
      {{ treeConfig.title }}
    </div>

    <div
      v-if="treeConfig.inputConfig"
      :style="treeConfig.inputStyle"
      class="input-filter-box"
    >
      <el-input
        v-model="filterText"
        :placeholder="
          treeConfig.inputConfig.placeholder || '输入关键字进行过滤'
        "
      />
    </div>

    <div v-if="treeConfig.btnList" class="btn-list-box">
      <template v-for="item in handleBtnList(treeConfig.btnList)">
        <el-button
          :key="item.id"
          size="small"
          class="btn-item"
          :type="item.type || 'primary'"
          :icon="item.icon || ''"
          :style="item.styleConfig || {}"
          v-bind="item.attrConfig || {}"
          @click="clickBtn(item)"
        >
          <span v-if="item.label">{{ item.label }}</span>
        </el-button>
      </template>
    </div>

    <div v-if="treeConfig.isExpandBtnList" class="btn-list-box expand-btn">
      <template v-for="item in expandBtnList">
        <el-button
          :key="item.id"
          size="small"
          class="btn-item"
          :type="item.type || 'primary'"
          :icon="item.icon || ''"
          :style="item.styleConfig || {}"
          v-bind="item.attrConfig || {}"
          @click="clickBtnIsExpand(item)"
        >
          <span v-if="item.label">{{ item.label }}</span>
        </el-button>
      </template>
    </div>

    <div
      v-loading="treeLoading"
      element-loading-text="拼命加载中"
      element-loading-spinner="el-icon-loading"
      element-loading-background="rgba(255, 255, 255, 1)"
      class="tree-box hover-show-scrollbar"
    >
      <el-tree
        v-if="refesh"
        ref="treeRef"
        :data="treeList"
        v-bind="attrConfig"
        :default-expanded-keys="
          attrConfig['default-expanded-keys'] || defaultExpandedKeys
        "
        :default-checked-keys="
          attrConfig['default-checked-keys'] || defaultCheckedKeys
        "
        :filter-node-method="filterNode"
        :default-expand-all="
          attrConfig['default-expand-all'] || defaultExpandAll
        "
        @check="handleCheck"
        @node-click="handleNodeClick"
      >
        <span
          slot-scope="{ node }"
          class="el-tree-node__label"
          @mouseenter="handleNodeMouseenter($event, node)"
        >
          <el-tooltip
            effect="light"
            :open-delay="300"
            :disabled="!node.isTootip"
            :content="node.label"
            placement="top-start"
          >
            <div class="label-cell">
              <span class="label-content">{{ node.label }}</span>
            </div>
          </el-tooltip>
        </span>
      </el-tree>
    </div>
  </div>
</template>

<script>
import { arr2tree } from '@/utils'
import { mapGetters } from 'vuex'

export default {
  name: 'TreeCard',
  props: {
    // 树配置
    treeConfig: {
      type: Object,
      default: () => ({})
    },
    // 树样式
    treeStyle: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      refesh: true,
      expandBtnList: [
        {
          label: '全部展开',
          type: 'default',
          icon: 'el-icon-s-unfold',
          id: 'expand-yes'
        },
        {
          label: '全部收起',
          type: 'default',
          icon: 'el-icon-s-fold',
          id: 'expand-no'
        }
      ],
      cacheList: [],
      treeLoading: false,
      treeList: [],
      defaultExpandAll: false,
      defaultExpandedKeys: [],
      defaultCheckedKeys: [],
      filterText: ''
    }
  },
  computed: {
    ...mapGetters(['authList']),
    /**
     * 处理按钮显示
     */
    handleBtnList() {
      return (list, type) => {
        const filterList =
          list.filter((e) => {
            if (e.authId) {
              return this.authList.find((f) => f.permission === e.authId)
            }
            return true
          }) || []

        return filterList
      }
    },
    // 属性配置
    attrConfig() {
      const config = {
        // 'node-key': 'id',
        // 'default-expanded-keys': [],
        // 'default-checked-keys': [],
        'show-checkbox': false,
        // 'default-expand-all': false,
        'highlight-current': true,
        props: { children: 'children', label: 'label' }
      }
      return Object.assign(config, this.treeConfig?.attrConfig || {})
    }
  },
  watch: {
    filterText(val) {
      this.$refs.treeRef?.filter(val)
    }
  },
  created() {
    this.getTreeData()
  },
  methods: {
    /**
     * 处理节点移入
     * @param {*} event 元素
     */
    handleNodeMouseenter(event, node) {
      const boxWidth = event.target.offsetWidth
      const child = event.target.querySelector('.label-content')
      if (child?.offsetWidth > boxWidth) {
        this.$set(node, 'isTootip', true)
      }
    },
    /**
     * 获取树列表数据
     * @param {*} obj 数据
     */
    async getTreeData(obj) {
      const { path, dataResolveConfig = {} } = this.treeConfig || {}
      if (!path) {
        return
      }
      this.treeLoading = true
      const params = {
        ...(obj || {})
      }
      try {
        const newPath = path.split('.')
        let api = this.$api
        newPath.forEach((e) => {
          api = api[e]
        })
        const res = await api(params)
        if (Number(res.code) === 1000) {
          const { dataType, keyProp } = dataResolveConfig
          const list =
            dataType === 'object' ? res.data[keyProp] || [] : res.data || []
          this.cacheList = JSON.parse(JSON.stringify(list))
          const treeList = arr2tree(list, dataResolveConfig)
          this.handleExpanded(treeList)
          this.treeList = treeList
        } else if (res.msg) {
          this.$message({ type: 'error', message: res.msg })
        }
      } catch (error) {
        //
      }

      this.treeLoading = false
    },
    /**
     * 处理默认展开
     * @param {*} data 数据
     */
    handleExpanded(treeList) {
      const { defaultExpandedIndex = [], dataResolveConfig = {} } =
        this.treeConfig || {}

      defaultExpandedIndex.forEach((indexStr) => {
        treeList.forEach((e, i) => {
          const iStr = `${i}`
          if (e.children && e.children.length > 0) {
            e.children.forEach((c, ci) => {
              const ciStr = `${iStr}${ci}`
              if (ciStr === indexStr) {
                if (c[dataResolveConfig.id]) {
                  this.defaultExpandedKeys.push(c[dataResolveConfig.id])
                }
              }
            })
          } else {
            if (iStr === indexStr) {
              if (e[dataResolveConfig.id]) {
                this.defaultExpandedKeys.push(e[dataResolveConfig.id])
              }
            }
          }
        })
      })
    },
    /**
     * 节点的显示过滤
     * @param {*} data 数据
     */
    filterNode(value, data) {
      const { props = {} } = this.attrConfig || {}
      if (!value) return true
      return data[props.label || 'label'].indexOf(value) !== -1
    },
    /**
     * 点击展开按钮
     * @param {*} item 数据
     */
    clickBtnIsExpand(item) {
      const { id } = item || {}
      // 展开收起
      // 避免重复点击触发渲染
      if (
        (id === 'expand-yes' && this.defaultExpandAll) ||
        (id === 'expand-no' && !this.defaultExpandAll)
      ) {
        return
      }
      this.refesh = false
      this.defaultExpandAll = id === 'expand-yes'
      this.$nextTick(() => {
        this.refesh = true
      })
    },
    /**
     * 点击按钮
     * @param {*} item 数据
     */
    clickBtn(item) {
      this.$emit('clickBtn', item)
    },
    /**
     * 处理子项code
     * @param {*} item 数据
     */
    handleChildCode(item) {
      const list = []
      const { props = {} } = this.attrConfig || {}
      const { dataResolveConfig = {} } = this.treeConfig || {}
      const {
        id = 'id',
        parentId = 'parentId',
        childrenKey = 'children'
      } = dataResolveConfig

      const cloneList = JSON.parse(JSON.stringify(this.cacheList))

      const map = {}
      for (const iterator of cloneList) {
        map[iterator[id]] = iterator
      }
      for (const iterator of cloneList) {
        const key = iterator[parentId]
        if (!(key in map)) continue
        map[key][childrenKey] = (map[key][childrenKey] || []).concat(iterator)
      }

      const curObj = map[item[id]] || {}

      const getChildData = (e) => {
        list.push(e[props.value])
        const childList = e[childrenKey] || []
        if (childList.length > 0) {
          childList.forEach((f) => {
            getChildData(f)
          })
        }
      }
      getChildData(curObj)

      return list
    },
    /**
     * 点击树节点
     * @param {*} data 数据
     */
    handleNodeClick(data) {
      const { childrenParams } = this.treeConfig || {}
      if (childrenParams) {
        const clilrenCode = this.handleChildCode(data)
        const obj = { ...(data || {}), childrenParams: clilrenCode }
        this.$emit('handleNodeClick', obj)
      } else {
        this.$emit('handleNodeClick', data)
      }
    },
    /**
     * 选中
     * @param {*} node 数据
     * @param {*} data 数据
     */
    handleCheck(node, data) {
      // checkedKeys 选中的key
      // halfCheckedKeys 半选的key
      this.$emit('handleCheck', { node, ...(data || {}) })
    }
  }
}
</script>

<style lang="scss" scoped>
.tree-card-box {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  color: #666;

  .title-box {
    display: flex;
    align-items: center;
    height: 50px;
    padding: 0 15px;
    color: #333;
    font-weight: 500;
    border-bottom: 1px solid #eee;
  }

  .btn-list-box {
    display: flex;
    justify-content: center;
    padding-top: 10px;

    .el-button {
      margin: 0 5px;
    }

    &.expand-btn {
      .el-button {
        width: 50%;
      }
    }

    .btn-item {
      padding: 7px 6px;
    }
  }

  .input-filter-box {
    padding: 10px 10px 0 10px;
  }

  .tree-box {
    padding: 0 10px;
    margin: 10px 0;
    flex: 1;
    overflow: auto;
  }

  ::v-deep .el-tree {
    padding-bottom: 80px;

    .el-tree-node__label,
    .label-cell {
      box-sizing: border-box;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      word-break: break-all;
    }
  }
}
</style>
